/*************************************************************
   Copyright(C) 2017 by MartyrCompany
   All rights reserved.
   
   CtrlItemDataHelper.cs
   UnityFramework
   
   Created by WuIslet on 2022-05-31.
   
*************************************************************/
#define USE_LUA_CODE1
#define USE_CSHARP_CODE
#define USE_EDITOR_UI_CONTROLDATA

using Framework.UI;
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

/// <summary>
/// 1. 代码自动生成总类。
/// 2. editor上按钮的调用方法。
/// </summary>
public class CtrlItemDataHelper
{
    #region public
    public static void AutoAddComponents(GameObject root, List<CtrlItemData> dataList)
    {
        SaveAllSample(dataList);
        var dic = new Dictionary<string, int>();
        var list = DFSinPrefab(root.transform, "UI_ControlSkip");
        for (int i = 0; i < list.Count; i++)
        {
            var tr = list[i];
            var hmiBase = tr.GetComponent<HMI_ComponentBase>();
            if ((!string.IsNullOrEmpty(tr.tag) && (tr.CompareTag("UI_ControlData"))) || (hmiBase != null && hmiBase.ExportToProgram()))
            {
                var name = tr.name;
                if (CheckDuplication(tr.GetUIRelativePath()))
                    continue;

                var data = GetAutoComponentCtrlItemData(tr);
                if (data != null)
                    dataList.Add(data);

                name = EditorToolsUtils.FormatProgramName(name);
                if (dic.ContainsKey(name))
                {
                    //dataList[dic[name]].isList = true;
                    //dataList[dic[name]].listName = name;
                    //data.isList = true;
                    //data.listName = name;
                }
                else
                {
                    dic.Add(name, dataList.Count - 1);
                }

            }
        }
    }
    
    public static void DeleteAllComponents(List<CtrlItemData> dataList)
    {
        dataList.Clear();
    }

    public static void AutoFormatPrefab(GameObject root, List<CtrlItemData> dataList)
    {
        for (int i = 0, imax = dataList.Count; i < imax; i++)
        {
            dataList[i].AutoFormatPrefab(root);
        }
    }

    public static void PrintAllPath(List<CtrlItemData> dataList)
    {
        if (dataList == null || dataList.Count == 0)
        {
            UnityEngine.Debug.LogError("没有数据");
            return;
        }

        var str = "";
        foreach (var dataCtrlItemData in dataList)
        {
            var o = dataCtrlItemData.GetTargets(null);

            var com = o as Component;
            if (com != null)
            {
                str += string.Format("{0}:{1}\n", dataCtrlItemData.name, com.gameObject.transform.GetPath());
                continue;
            }
            var go = o as GameObject;
            if (go != null)
            {
                str += string.Format("{0}:{1}\n", dataCtrlItemData.name, go.transform.GetPath());
                continue;
            }
            str += string.Format("{0}:{1}\n", dataCtrlItemData.name, "null");
        }

        UnityEngine.Debug.LogError(str);
    }

    public static int AutoFindComponents(GameObject root, List<CtrlItemData> dataList)
    {
        var AllTranList = DFSinPrefab(root.transform, "UI_ControlSkip");
        var AllObjectId = new Dictionary<string, GameObject>(AllTranList.Count);
        for (int i = 0; i < AllTranList.Count; i++)
        {
            var go = AllTranList[i].gameObject;
            var goid = UnityEditor.GlobalObjectId.GetGlobalObjectIdSlow(go);
            if (goid.targetObjectId != 0)
                AllObjectId.Add(goid.ToString(), go);
        }

        var failCount = 0;
        for (int i = 0; i < dataList.Count; i++)
        {
            var ctrlItemData = dataList[i];
            if (ctrlItemData.GetTargets(root) == null)
            {
                GameObject findGo;
                if (AllObjectId.TryGetValue(ctrlItemData.TargetFileID, out findGo))
                {
                    ctrlItemData.SetTarget(findGo, ctrlItemData.type, true);
                }
                else
                {
                    var name = CtrlItemDataDefaultFormatHelper.ToUpperFirst(ctrlItemData.name);
                    GameObject find = null;
                    var duplication = false;
                    for (int j = 0; j < AllTranList.Count; j++)
                    {
                        var target = AllTranList[j];
                        if (target.name == name || target.name == ctrlItemData.name)
                        {
                            if (find == null)
                            {
                                find = target.gameObject;
                            }
                            else
                            {
                                duplication = true;
                            }
                        }
                    }
                    if (find != null && !duplication)
                    {
                        ctrlItemData.SetTarget(find, ctrlItemData.type, true);
                    }
                    else
                    {
                        ++failCount;
                    }
                }
            }
        }

        return failCount;
    }

    private static List<Transform> BFSPrefab(Transform go, Func<Transform, bool> filter)
    {
        List<Transform> result = new List<Transform>();
        result.Add(go);
        int head = 0;
        int tail = 1;
        while (head != tail)
        {
            var curGo = result[head];
            head++;
            for (int i = 0; i < curGo.childCount; ++i)
            {
                var childTr = curGo.GetChild(i);
                result.Add(childTr);
                tail++;
            }
        }

        if (filter != null)
        {
            for (int i = result.Count - 1; i >= 0; --i)
            {
                if (!filter(result[i]))
                {
                    result.RemoveAt(i);
                }
            }
        }
        return result;
    }

    private static CtrlItemDataHelper tmpClass = new CtrlItemDataHelper();
    public static string GetReflectCode(string name, UIEditorData uiData)
    {
        var str = "";
        if (name.StartsWith("_"))
        {
            try
            {
                var value = ReflectionHelper.GetValue(tmpClass, name) as string;
                if (value != null)
                {
                    str = value;
                }
            }
            catch { }
        }
        else
        {
            try
            {
                var value = ReflectionHelper.InvokMethod(tmpClass, name, uiData) as string;
                if (value != null)
                {
                    str = value;
                }
            }
            catch { }
        }

        return str;
    }
    #endregion public

    #region private
    private static string GetViewName(UIEditorData uiData) //reflect
    {
        return uiData.GetScriptSymbol();
    }
    public static string GetViewModelName(UIEditorData uiData) //reflect
    {
        var scriptSymbol = uiData.GetScriptSymbol();

        if (uiData.isChild == 0)
        {
            return scriptSymbol + "Window";
        }
        else
        {
            return scriptSymbol + "Child";
        }
        return scriptSymbol + "Window";
    }
    public static string GetGridSetupFunc(UIEditorData uiData) //reflect
    {
        if (uiData.isChild == 2)
        {
            if (uiData.resUIID < 10000) //container
                return string.Format("GridTools.setupContainerView(self, {0})", uiData.resUIID);
            else //grid
                return string.Format("GridTools.setupGridView(self, {0})", uiData.resUIID);
        }
        return "";
    }

    private static CtrlItemDataDefaultFormatHelper GetHelper(CtrlItemData data)
    {
        var list = UIControlDataType.GetList();
        var index = UIControlDataType.FindType(data.type);
        if (index < 0)
        {
            var defaultHelper = new CtrlItemDataDefaultFormatHelper();
            defaultHelper.SetData(data);
            return defaultHelper;
        }
        var helper = list[index].helper;
        helper.SetData(data);
        return helper;
    }

    private static List<Transform> DFSinPrefab(Transform root, string skipTag)
    {
        var list = new List<Transform>();
        if (root != null)
        {
            list.Add(root);

            for (int i = 0; i < root.childCount; i++)
            {
                if (!string.IsNullOrEmpty(skipTag) && root.GetChild(i).CompareTag(skipTag))
                    continue;

                DFS(root.GetChild(i), list, skipTag);
            }
        }
        return list;
    }

    private static void DFS(Transform parent, List<Transform> list, string skipTag)
    {
        list.Add(parent);
        for (int i = 0; i < parent.childCount; i++)
        {
            if (!string.IsNullOrEmpty(skipTag) && parent.GetChild(i).CompareTag(skipTag))
                continue;
            DFS(parent.GetChild(i), list, skipTag);
        }
    }

    private static List<string> allSimple = new List<string>();
    private static void SaveAllSample(List<CtrlItemData> dataList)
    {
        allSimple.Clear();
        for (int i = 0; i < dataList.Count; i++)
        {
            var data = dataList[i];
            allSimple.Add(data.targetsPath);
        }
    }

    private static bool CheckDuplication(string key)
    {
        return allSimple.Contains(key);
    }

    private static CtrlItemData GetAutoComponentCtrlItemData(Transform target)
    {
        var name = EditorToolsUtils.FormatProgramName(target.name);
        var go = target.gameObject;
        var path = target.GetUIRelativePath();

        var data = new CtrlItemData();
        data.name = name;
        data.SetTarget(go, EUIControlDataType.None);
        return data;
    }
    #endregion private

    #region CodeGenerator
#if USE_CSHARP_CODE
    //public static void CopyViewModelChildToClipBoardImpl(UIEditorData uiData)
    //{
    //    StringBuilder sb = new StringBuilder(1024);
    //    sb.AppendFormat("#region 控件初始化，自动生成请勿手改 <{0}>\r\n", uiData.ScriptSymbol);
    //    foreach (var ctrl in uiData.ctrlItemDatas)
    //    {
    //        var str = GetHelper(ctrl).GetCSharpViewModuleChildClickRegister();
    //        if (!string.IsNullOrEmpty(str))
    //        {
    //            sb.Append(str);
    //        }
    //    }
        
    //    sb.AppendFormat("#endregion 控件初始化，自动生成请勿手改 <{0}>\r\n", uiData.ScriptSymbol);

    //    sb.AppendFormat("#region 注册按钮事件 <{0}>\r\n", uiData.ScriptSymbol);
    //    foreach (var ctrl in uiData.ctrlItemDatas)
    //    {
    //        var str = GetHelper(ctrl).GetCSharpViewModuleChildClickFunction();
    //        if (!string.IsNullOrEmpty(str))
    //        {
    //            sb.Append(str);
    //        }
    //    }
    //    sb.AppendFormat("#endregion 注册按钮事件 <{0}>\r\n", uiData.ScriptSymbol);

    //    GUIUtility.systemCopyBuffer = sb.ToString();
    //}
    
    public static void CopyViewModelToClipBoardImpl(UIEditorData uiData, bool withClickFunc) //ViewModel
    {
        StringBuilder sb = new StringBuilder(1024);
//        sb.AppendFormat("#region 控件绑定变量声明，自动生成请勿手改 <{0}>\r\n", uiData.ScriptSymbol);
//#if !USE_EDITOR_UI_CONTROLDATA
//        sb.AppendFormat("        {0} UIControlData mUIData;\r\n", accessLevel);
//#endif
//        foreach (var ctrl in uiData.ctrlItemDatas)
//        {
//            var str = GetHelper(ctrl).GetCSharpViewModleDefineCode("public");
//            if (!string.IsNullOrEmpty(str))
//            {
//                sb.Append(str);
//            }
//        }
//        sb.AppendFormat("\r\n");
//        sb.AppendFormat("#endregion 控件绑定变量声明，自动生成请勿手改 <{0}>\r\n", uiData.ScriptSymbol);

//        sb.AppendFormat("#region 控件初始化，自动生成请勿手改 <{0}>\r\n", uiData.ScriptSymbol);
//        sb.Append("        base.OnInit();\r\n");
//        foreach (var ctrl in uiData.ctrlItemDatas)
//        {
//            var str = GetHelper(ctrl).GetCSharpViewModelRegister();
//            if (!string.IsNullOrEmpty(str))
//            {
//                sb.Append(str);
//            }
//        }
//        sb.AppendFormat("#endregion 控件初始化，自动生成请勿手改 <{0}>\r\n", uiData.ScriptSymbol);
        
        if (withClickFunc)
        {
            sb.AppendFormat("#region 注册按钮事件 <{0}>\r\n", uiData.ScriptSymbol);
            foreach (var ctrl in uiData.ctrlItemDatas)
            {
                var str = GetHelper(ctrl).GetCSharpViewModelFunc();
                if (!string.IsNullOrEmpty(str))
                {
                    sb.Append(str);
                }
            }
            sb.AppendFormat("#endregion 注册按钮事件 <{0}>\r\n", uiData.ScriptSymbol);
        }

        GUIUtility.systemCopyBuffer = sb.ToString();
    }

    #region Template
    public static string GetCSharpDefineCode(UIEditorData uiData) //reflect //View
    {
        var accessLevel = "public";
        StringBuilder sb = new StringBuilder(1024);
#if !USE_EDITOR_UI_CONTROLDATA
        sb.AppendFormat("    {0} UIControlData mUIData;\r\n", accessLevel);
#endif
        foreach (var ctrl in uiData.ctrlItemDatas)
        {
            var a = GetHelper(ctrl);
            var str = GetHelper(ctrl).GetCSharpDefineCode(accessLevel);
            if (!string.IsNullOrEmpty(str))
            {
                sb.Append(str);
            }
        }
        return sb.ToString();
    }

    public static string GetCSharpInitCode(UIEditorData uiData) //reflect //View
    {
        StringBuilder sb = new StringBuilder(1024);
#if !USE_EDITOR_UI_CONTROLDATA
        sb.Append("        mUIData = mGameObject.GetComponent<UIControlData>();\r\n");
#endif
        foreach (var ctrl in uiData.ctrlItemDatas)
        {
            var a = GetHelper(ctrl);
            var str = GetHelper(ctrl).GetCSharpInitCode();
            if (!string.IsNullOrEmpty(str))
            {
                sb.Append(str);
            }
        }
        return sb.ToString();
    }
    public static string GetCSharpAddClickCode(UIEditorData uiData) //reflect //View
    {
        StringBuilder sb = new StringBuilder(1024);
        foreach (var ctrl in uiData.ctrlItemDatas)
        {
            var a = GetHelper(ctrl);
            var str = GetHelper(ctrl).GetCSharpAddClickCode();
            if (!string.IsNullOrEmpty(str))
            {
                sb.Append(str);
            }
        }
        return sb.ToString();
    }
    public static string GetCSharpBindTextCode(UIEditorData uiData) //reflect //View
    {
        StringBuilder sb = new StringBuilder(1024);
        foreach (var ctrl in uiData.ctrlItemDatas)
        {
            var a = GetHelper(ctrl);
            var str = GetHelper(ctrl).GetCSharpBindTextCode();
            if (!string.IsNullOrEmpty(str))
            {
                sb.Append(str);
            }
        }
        return sb.ToString();
    }
    public static string GetCSharpClickFuncCode(UIEditorData uiData) //reflect //View
    {
        StringBuilder sb = new StringBuilder(1024);
        foreach (var ctrl in uiData.ctrlItemDatas)
        {
            var a = GetHelper(ctrl);
            var str = GetHelper(ctrl).GetCSharpClickFuncCode();
            if (!string.IsNullOrEmpty(str))
            {
                sb.Append(str);
            }
        }
        return sb.ToString();
    }
        #endregion Template
#endif
#if USE_LUA_CODE
    public static void CopyCodeToClipBoardImpl(string accessLevel, UIEditorData uiData)
    {
    }
    
    public static void CopyInitCodeToClipBoardImpl(UIEditorData uiData)
    {
    }

    /// <summary>
    /// 用来给额外需要写注册的地方复制用的
    /// </summary>
    public static void CopyViewModelChildToClipBoardImpl(UIEditorData uiData)
    {
        StringBuilder sb = new StringBuilder(1024);
        GUIUtility.systemCopyBuffer = sb.ToString();
    }

    /// <summary>
    /// 用来给viewmodel的模板复制。
    /// </summary>
    public static void CopyViewModelToClipBoardImpl(UIEditorData uiData, bool withClickFunc)
    {
        StringBuilder sb = new StringBuilder(1024);
        var str = "";
        str = GetLuaCopyViewModelInit(uiData);
        sb.Append(str);

        if (withClickFunc)
        {
            str = GetLuaCopyViewModelClick(uiData);
            sb.Append(str);
        }

        GUIUtility.systemCopyBuffer = sb.ToString();
    }

        #region Template
    public static string GetLuaInitCode(UIEditorData uiData) //reflect
    {
        StringBuilder sb = new StringBuilder(1024);
        foreach (var ctrl in uiData.ctrlItemDatas)
        {
            var str = GetHelper(ctrl).GetLuaInitCode();
            if (!string.IsNullOrEmpty(str))
            {
                sb.Append(str);
            }
        }
        return sb.ToString();
    }

    public static string GetLuaExtraFuncCode(UIEditorData uiData) //reflect
    {
        var viewName = GetViewName(uiData);
        StringBuilder sb = new StringBuilder(1024);
        sb.AppendFormat("function {0}:{1}()\r\n", viewName, uiData.isChild == 0 ? "onOpen" : "onOpenChildWindow");
        foreach (var ctrl in uiData.ctrlItemDatas)
        {
            var str = GetHelper(ctrl).GetLuaExtraFuncCode(true);
            if (!string.IsNullOrEmpty(str))
            {
                sb.Append(str);
            }
        }
        sb.AppendFormat("end\r\n\r\n");

        sb.AppendFormat("function {0}:{1}()\r\n", viewName, uiData.isChild == 0 ? "onClose" : "onCloseChildWindow");
        foreach (var ctrl in uiData.ctrlItemDatas)
        {
            var str = GetHelper(ctrl).GetLuaExtraFuncCode(false);
            if (!string.IsNullOrEmpty(str))
            {
                sb.Append(str);
            }
        }
        sb.AppendFormat("end\r\n");
        return sb.ToString();
    }

    public static string GetLuaCopyViewModelInit(UIEditorData uiData) //reflect
    {
        var viewName = GetViewName(uiData);
        var viewPath = "UI/MVVM/GenerateCode/" + viewName;
        var viewModelName = GetViewModelName(uiData);
        StringBuilder sb = new StringBuilder(1024);
        sb.AppendFormat("-- 控件初始化，自动生成请勿手改 start <{0}>\r\n", viewModelName);
        sb.AppendFormat("    self.defaultViewName = \"{0}\"\r\n", (uiData.isChild == 0 || uiData.isChild == 1) ? viewName : viewPath);
        sb.AppendFormat("    self.prefabPath = nil\r\n");
        sb.AppendFormat("    local BindableProp = BindableProp\r\n");
        foreach (var ctrl in uiData.ctrlItemDatas)
        {
            var str = GetHelper(ctrl).GetLuaViewModelBindProp_new();
            if (!string.IsNullOrEmpty(str))
            {
                sb.Append(str);
            }
        }

        var listDic = new Dictionary<string, List<string>>();
        foreach (var ctrl in uiData.ctrlItemDatas)
        {
            var listnames = new List<string>();
            var propnames = new List<string>();
            if (ctrl.isList && !string.IsNullOrEmpty(ctrl.listName))
            {
                var propName = GetHelper(ctrl).GetPropName();
                if (ctrl.type == EUIControlDataType.RedDot || ctrl.type == EUIControlDataType.Button)
                {

                }
                else
                {
                    listnames.Add(ctrl.listName);
                    propnames.Add(propName);
                }

                for (int i = 0; i < CtrlItemData.BindAllTypes.Count; ++i)
                {
                    var type = CtrlItemData.BindAllTypes[i];
                    if (ctrl.GetBindFlag(type))
                    {
                        var typeName = type.ToString();
                        listnames.Add(string.Format("{0}{1}", ctrl.listName, typeName));
                        propnames.Add(string.Format("{0}{1}", propName, typeName));
                    }
                }
            }

            for (int i = 0; i < listnames.Count; i++)
            {
                var listname = listnames[i];
                var propname = propnames[i];

                if (!listDic.ContainsKey(listname))
                {
                    listDic.Add(listname, new List<string>());
                }
                listDic[listname].Add(propname);
            }
        }

        foreach (var kv in listDic)
        {
            sb.AppendFormat("    self.{0} = {{", kv.Key);
            for (var i = 0; i < kv.Value.Count; i++)
            {
                sb.AppendFormat("self.{0}, ", kv.Value[i]);
            }
            sb.AppendFormat("}}\r\n");
        }

        sb.AppendFormat("-- 控件初始化，自动生成请勿手改 end <{0}>\r\n", viewModelName);
        return sb.ToString();
    }

    public static string GetLuaCopyViewModelClick(UIEditorData uiData) //reflect
    {
        var viewModelName = GetViewModelName(uiData);
        StringBuilder sb = new StringBuilder(1024);
        sb.AppendFormat("-- 注册按钮事件 start <{0}>\r\n", viewModelName);
        foreach (var ctrl in uiData.ctrlItemDatas)
        {
            var str = GetHelper(ctrl).GetLuaViewModelFunc(viewModelName);
            if (!string.IsNullOrEmpty(str))
            {
                sb.Append(str);
            }
        }
        sb.AppendFormat("-- 注册按钮事件 end <{0}>\r\n", viewModelName);
        return sb.ToString();
    }

    public static string GetLuaBindExtraFuncCode(UIEditorData uiData) //reflect
    {
        var viewName = GetViewName(uiData);
        StringBuilder sb = new StringBuilder(1024);
        foreach (var ctrl in uiData.ctrlItemDatas)
        {
            var str = GetHelper(ctrl).GetLuaBindExtraFuncCode(viewName);
            if (!string.IsNullOrEmpty(str))
            {
                sb.Append(str);
            }
        }
        return sb.ToString();
    }
        #endregion Template
#endif
    #endregion CodeGenerator
}